'''
Created on Apr 3, 2011

@author: georgeholler
'''

import sys
if sys.version < '2.7':
   print 'You must run with Python version 2.7 or greater.'
   sys.exit(1)
   
import logging

from options import Options

from xml.sax import saxutils
from google.appengine.ext.remote_api import remote_api_stub
from google.appengine.ext import db
from google.appengine.api import datastore
from google.appengine.api import memcache

class ExportFormatter:
    def get_header(self):
        return ''
    def get_item(self, item):
        return 'item = ' + str(item) + '\n'
    def get_footer(self):
        return ''

class DefaultXMLExportFormatter(ExportFormatter):
    def get_header(self):
        return '<items>\n'
    def get_item(self, item):
        s = '   <' + item.kind().lower() + '>\n'
        for name in item.dynamic_properties():
            value = saxutils.escape(unicode(item.__getattr__(name))).encode('UTF-8')
            s += '      <'+name+'>'+value+'</'+name+'>\n'
        s += '   </' + item.kind().lower() + '>\n'
        return s
    def get_footer(self):
        return '</items>\n'        
    

class Main:
    
    def __init__(self):
        self.kinds = {}
    
    def connect(self, options):
        def getauth():
            return options.email, options.password
        remote_api_stub.ConfigureRemoteDatastore(options.appid, '/remote_api', getauth, options.host)
    
    def createExpandoClass(self, name):
        if not self.kinds.has_key(name):
            self.kinds[name] = 1
            logging.info('Adding entity: ' + name)
            exec('class ' + name + '(db.Expando):\n   pass\n')

    def filterStats(self, list):
        filtered = []
        for item in list:
            if not item.kind().startswith('_'):
                filtered.append(item)
        return filtered

    def delete_entity(self, fetch_count=100, entity=None):
        if entity:
            self.createExpandoClass(entity)
        while True:
            if entity:
                q = db.GqlQuery('SELECT __key__ from ' + entity).fetch(fetch_count)
            else:
                q = db.GqlQuery('SELECT __key__').fetch(fetch_count)
                q = self.filterStats(q)
            if len(q) == 0:
                break
            if entity:
                logging.info('Deleting ' + str(len(q)) + ' entities (' + entity + ')')
            else:
                logging.info('Deleting ' + str(len(q)) + ' entities')
            datastore.Delete(q)
        client = memcache.Client()
        client.flush_all()

    def delete_action(self, options):
        logging.info('Clearing the database for ' + options.appid);
        self.connect(options)
        if options.entities is None or len(options.entities) == 0:
            self.delete_entity(fetch_count=options.fetch_count)
        else:
            for entity in options.entities:
                self.delete_entity(fetch_count=options.fetch_count, entity=entity)

    def clear_cache_action(self, options):
        logging.info('Clearing the cache for ' + options.appid);
        self.connect(options)
        memcache.Client().flush_all()
        logging.info('Done')
    
    def main(self, argv):
        print 'Adept - The Appengine Datastore Expert Power Tool'
        logging.basicConfig(filename='adept.log', format='%(asctime)s %(levelname)-8s %(message)s',
            level=logging.INFO, filemode='w')    
        console = logging.StreamHandler(sys.stdout)
        console.setLevel(logging.INFO)
        formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s')
        console.setFormatter(formatter)    
        logging.getLogger('').addHandler(console)
        options = Options()
        options.parse(argv)
        if options.action == 'delete':
            self.delete_action(options)
        elif options.action == 'clear-cache':
            self.clear_cache_action(options)
    
if __name__ == '__main__':
    app = Main()
    app.main(sys.argv[1:])
    